package com.mz.util;

import java.io.BufferedReader; 
import java.io.DataInputStream; 
import java.io.DataOutputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStreamReader; 
import java.io.OutputStream; 
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.Socket;
import java.net.URL; 
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map; 
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

/**
 * 缃戠粶璇锋眰宸ュ叿绫�<br />
 * Created by <b>The.Sunshine</b> on 2018/08/1.<br />
 * 姝ゅ伐鍏风被鍖呭惈浜嗙綉缁滆姹傜殑甯歌鎿嶄綔濡傦細
 * <ul>
 * 	<li>璇锋眰鐘舵�佺爜</li>
 * 	<li>鍙戦�丳OST銆丟ET璇锋眰</li>
 * 	<li>鑾峰彇IP/MAC鍦板潃</li>
 * 	<li>Socket鐨勫熀鏈搷浣�</li>
 * 	<li>IP/绔彛鐨勬娴�</li>
 * </ul>
 * @author The.Sunshine 
 * @version 1.0
 */
public class NetworkTools {
	private static List<String> sessionList=new LinkedList<>();
	/**
	 * HTTP Status-Code 200: OK.
	 */
	public static final int HTTP_CODE_OK = 200;

	/**
	 * HTTP Status-Code 201: Created.
	 */
	public static final int HTTP_CODE_CREATED = 201;

	/**
	 * HTTP Status-Code 202: Accepted.
	 */
	public static final int HTTP_CODE_ACCEPTED = 202;

	/**
	 * HTTP Status-Code 203: Non-Authoritative Information.
	 */
	public static final int HTTP_CODE_NOT_AUTHORITATIVE = 203;

	/**
	 * HTTP Status-Code 204: No Content.
	 */
	public static final int HTTP_CODE_NO_CONTENT = 204;

	/**
	 * HTTP Status-Code 205: Reset Content.
	 */
	public static final int HTTP_CODE_RESET = 205;

	/**
	 * HTTP Status-Code 206: Partial Content.
	 */
	public static final int HTTP_CODE_PARTIAL = 206;

	/* 3XX: relocation/redirect */

	/**
	 * HTTP Status-Code 300: Multiple Choices.
	 */
	public static final int HTTP_CODE_MULT_CHOICE = 300;

	/**
	 * HTTP Status-Code 301: Moved Permanently.
	 */
	public static final int HTTP_CODE_MOVED_PERM = 301;

	/**
	 * HTTP Status-Code 302: Temporary Redirect.
	 */
	public static final int HTTP_CODE_MOVED_TEMP = 302;

	/**
	 * HTTP Status-Code 303: See Other.
	 */
	public static final int HTTP_CODE_SEE_OTHER = 303;

	/**
	 * HTTP Status-Code 304: Not Modified.
	 */
	public static final int HTTP_CODE_NOT_MODIFIED = 304;

	/**
	 * HTTP Status-Code 305: Use Proxy.
	 */
	public static final int HTTP_CODE_USE_PROXY = 305;

	/* 4XX: client error */

	/**
	 * HTTP Status-Code 400: Bad Request.
	 */
	public static final int HTTP_CODE_BAD_REQUEST = 400;

	/**
	 * HTTP Status-Code 401: Unauthorized.
	 */
	public static final int HTTP_CODE_UNAUTHORIZED = 401;

	/**
	 * HTTP Status-Code 402: Payment Required.
	 */
	public static final int HTTP_CODE_PAYMENT_REQUIRED = 402;

	/**
	 * HTTP Status-Code 403: Forbidden.
	 */
	public static final int HTTP_CODE_FORBIDDEN = 403;

	/**
	 * HTTP Status-Code 404: Not Found.
	 */
	public static final int HTTP_CODE_NOT_FOUND = 404;

	/**
	 * HTTP Status-Code 405: Method Not Allowed.
	 */
	public static final int HTTP_CODE_BAD_METHOD = 405;

	/**
	 * HTTP Status-Code 406: Not Acceptable.
	 */
	public static final int HTTP_CODE_NOT_ACCEPTABLE = 406;

	/**
	 * HTTP Status-Code 407: Proxy Authentication Required.
	 */
	public static final int HTTP_CODE_PROXY_AUTH = 407;

	/**
	 * HTTP Status-Code 408: Request Time-Out.
	 */
	public static final int HTTP_CODE_CLIENT_TIMEOUT = 408;

	/**
	 * HTTP Status-Code 409: Conflict.
	 */
	public static final int HTTP_CODE_CONFLICT = 409;

	/**
	 * HTTP Status-Code 410: Gone.
	 */
	public static final int HTTP_CODE_GONE = 410;

	/**
	 * HTTP Status-Code 411: Length Required.
	 */
	public static final int HTTP_CODE_LENGTH_REQUIRED = 411;

	/**
	 * HTTP Status-Code 412: Precondition Failed.
	 */
	public static final int HTTP_CODE_PRECON_FAILED = 412;

	/**
	 * HTTP Status-Code 413: Request Entity Too Large.
	 */
	public static final int HTTP_CODE_ENTITY_TOO_LARGE = 413;

	/**
	 * HTTP Status-Code 414: Request-URI Too Large.
	 */
	public static final int HTTP_CODE_REQ_TOO_LONG = 414;

	/**
	 * HTTP Status-Code 415: Unsupported Media Type.
	 */
	public static final int HTTP_CODE_UNSUPPORTED_TYPE = 415;

	/* 5XX: server error */

	/**
	 * HTTP Status-Code 500: Internal Server Error.
	 */
	public static final int HTTP_CODE_INTERNAL_ERROR = 500;

	/**
	 * HTTP Status-Code 501: Not Implemented.
	 */
	public static final int HTTP_CODE_NOT_IMPLEMENTED = 501;

	/**
	 * HTTP Status-Code 502: Bad Gateway.
	 */
	public static final int HTTP_CODE_BAD_GATEWAY = 502;

	/**
	 * HTTP Status-Code 503: Service Unavailable.
	 */
	public static final int HTTP_CODE_UNAVAILABLE = 503;

	/**
	 * HTTP Status-Code 504: Gateway Timeout.
	 */
	public static final int HTTP_CODE_GATEWAY_TIMEOUT = 504;

	/**
	 * HTTP Status-Code 505: HTTP Version Not Supported.
	 */
	public static final int HTTP_CODE_VERSION = 505;
	
	/**
	 * 鏈満鍥炵幆(IP)鍦板潃
	 */
	public static final String LOCALHOST_IP="127.0.0.1";
	
	/** 
	 * 发送GET请求 
	 * 
	 * @param requestUrl 
	 *      请求url 
	 * @param requestHeader 
	 *      请求头 
	 * @param responseEncoding 
	 *      响应编码 
	 * @return 页面响应html 
	 */
	public static String sendGet(String requestUrl, Map<String, String> requestHeader, String responseEncoding) { 
		String result = ""; 
		BufferedReader reader = null; 
		try { 
			if (StringUtil.isBlank(requestUrl)) { 
				return result; 
			} 
			URL realUrl = new URL(requestUrl); 
			URLConnection connection = realUrl.openConnection(); 
			connection.setRequestProperty("accept", "text/html, application/xhtml+xml, image/jxr, */*"); 
			connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0"); 
			if (requestHeader != null && requestHeader.size() > 0) { 
				for (Entry<String, String> entry : requestHeader.entrySet()) { 
					connection.setRequestProperty(entry.getKey(), entry.getValue()); 
				} 
			} 
			connection.connect(); 
			if (StringUtil.isBlank(responseEncoding)) { 
				responseEncoding = "UTF-8"; 
			} 
			reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), responseEncoding)); 
			String line; 
			while ((line = reader.readLine()) != null) { 
				result += line; 
			} 
		} catch (Exception e) { 
			System.out.println("Send GET Request Exception!"); 
			e.printStackTrace(); 
		} finally { 
			try { 
				if (reader != null) { 
					reader.close(); 
				} 
			} catch (Exception e) { 
				e.printStackTrace(); 
			} 
		} 
		return result; 
	} 
	
	/** 
	 * 发送POST请求
	 *  
	 * @param requestUrl 
	 *      请求url 
	 * @param requestHeader 
	 *      请求头 
	 * @param formTexts 
	 *      表单数据 
	 * @param files 
	 *      上传文件 
	 * @param requestEncoding 
	 *      请求编码 
	 * @param responseEncoding 
	 *      响应编码 
	 * @param sessionFlag  是否保存会话(session)
	 *      true:保存,false：不保存
	 * @return 页面响应html 
	 */ 
	public static String sendPost(String requestUrl, Map<String, String> requestHeader, Map<String, String> formTexts, Map<String, String> files, String requestEncoding, String responseEncoding, boolean sessionFlag) { 
		OutputStream out = null; 
		BufferedReader reader = null; 
		String result = ""; 
		try { 
			if (StringUtil.isBlank(requestUrl)) { 
				return result; 
			} 
			URL realUrl = new URL(requestUrl); 
			HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); 
			connection.setRequestProperty("accept", "text/html, application/xhtml+xml, image/jxr, */*"); 
			connection.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0"); 
			if (requestHeader != null && requestHeader.size() > 0) { 
				for (Entry<String, String> entry : requestHeader.entrySet()) { 
					connection.setRequestProperty(entry.getKey(), entry.getValue()); 
				} 
			} 
			connection.setDoOutput(true); 
			connection.setDoInput(true); 
			connection.setRequestMethod("POST"); 
			if(sessionList.size()>0 && sessionFlag){
				connection.setRequestProperty("Cookie", sessionList.get(0));
			}
			if (StringUtil.isBlank(requestEncoding)) { 
				requestEncoding = "UTF-8"; 
			} 
			if (StringUtil.isBlank(responseEncoding)) { 
				responseEncoding = "UTF-8"; 
			} 
			if (requestHeader != null && requestHeader.size() > 0) { 
				for (Entry<String, String> entry : requestHeader.entrySet()) { 
					connection.setRequestProperty(entry.getKey(), entry.getValue()); 
				} 
			} 
			if (files == null || files.size() == 0) { 
				connection.setRequestProperty("content-type", "application/x-www-form-urlencoded"); 
				out = new DataOutputStream(connection.getOutputStream()); 
				if (formTexts != null && formTexts.size() > 0) { 
					String formData = ""; 
					for (Entry<String, String> entry : formTexts.entrySet()) { 
						formData += entry.getKey() + "=" + entry.getValue() + "&"; 
					} 
					formData = formData.substring(0, formData.length() - 1); 
					out.write(formData.toString().getBytes(requestEncoding)); 
				} 
			} else { 
				String boundary = "-----------------------------" + String.valueOf(new Date().getTime()); 
				connection.setRequestProperty("content-type", "multipart/form-data; boundary=" + boundary); 
				out = new DataOutputStream(connection.getOutputStream()); 
				if (formTexts != null && formTexts.size() > 0) { 
					StringBuilder sbFormData = new StringBuilder(); 
					for (Entry<String, String> entry : formTexts.entrySet()) { 
						sbFormData.append("--" + boundary + "\r\n"); 
						sbFormData.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"\r\n\r\n"); 
						sbFormData.append(entry.getValue() + "\r\n"); 
					} 
					out.write(sbFormData.toString().getBytes(requestEncoding)); 
				} 
				for (Entry<String, String> entry : files.entrySet()) { 
					String fileName = entry.getKey(); 
					String filePath = entry.getValue(); 
					if (StringUtil.isBlank(fileName) || StringUtil.isBlank(filePath)) { 
						continue; 
					} 
					File file = new File(filePath); 
					if (!file.exists()) { 
						continue; 
					} 
					out.write(("--" + boundary + "\r\n").getBytes(requestEncoding)); 
					out.write(("Content-Disposition: form-data; name=\"" + fileName + "\"; filename=\"" + file.getName() + "\"\r\n").getBytes(requestEncoding)); 
					out.write(("Content-Type: application/x-msdownload\r\n\r\n").getBytes(requestEncoding)); 
					DataInputStream in = new DataInputStream(new FileInputStream(file)); 
					int bytes = 0; 
					byte[] bufferOut = new byte[1024]; 
					while ((bytes = in.read(bufferOut)) != -1) { 
						out.write(bufferOut, 0, bytes); 
					} 
					in.close(); 
					out.write(("\r\n").getBytes(requestEncoding)); 
				} 
				out.write(("--" + boundary + "--").getBytes(requestEncoding)); 
			} 
			out.flush(); 
			out.close(); 
			out = null; 
			reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), responseEncoding)); 
			String line; 
			while ((line = reader.readLine()) != null) { 
				result += line; 
			} 
			if(sessionFlag){
				String session_value = connection.getHeaderField("Set-Cookie");
				if(session_value!=null){
					String[] sessionId = session_value.split(";");
					sessionList.add(sessionId[0]);
				}
			}
		} catch (Exception e) { 
			System.out.println("Send POST Request Exception锛�"); 
			e.printStackTrace(); 
		} finally { 
			try { 
				if (out != null) { 
					out.close(); 
				} 
				if (reader != null) { 
					reader.close(); 
				} 
			} catch (IOException ex) { 
				ex.printStackTrace(); 
			} 
		} 
		return result; 
	}
	
	/**
	 * 灏唕equest璇锋眰瀵硅薄杞崲涓篗ap闆嗗悎
	 * @param req
	 * @return
	 */
	public static Map<String,Object> getRequestToMap(HttpServletRequest req)
	{
		Map<String,Object> retMap = new HashMap<>();
		Map<String, String[]> map1 = req.getParameterMap();
		for(Iterator<String> it = map1.keySet().iterator();it.hasNext();)
		{
			String key  = (String)it.next();
			retMap.put(key, req.getParameter(key));
		}
		return retMap;
	}
	
	
	/**
	 * 鏍规嵁long鍊艰幏鍙朓P v4鍦板潃
	 * @param longIP IP鐨刲ong琛ㄧず褰㈠紡
	 * @return IP V4 鍦板潃
	 */
	public static String longToIpv4(long longIP) {
		final StringBuilder sb = new StringBuilder();
		sb.append(String.valueOf(longIP >>> 24));
		sb.append(".");
		sb.append(String.valueOf((longIP & 0x00FFFFFF) >>> 16));
		sb.append(".");
		sb.append(String.valueOf((longIP & 0x0000FFFF) >>> 8));
		sb.append(".");
		sb.append(String.valueOf(longIP & 0x000000FF));
		return sb.toString();
	}

	/**
	 * 鏍规嵁IP鍦板潃璁＄畻鍑簂ong鍨嬬殑鏁版嵁
	 * @param strIP IP V4 鍦板潃
	 * @return long鍊�
	 */
//	public static long ipv4ToLong(String strIP) {
//		if (RegexTools.isIp(strIP)) {
//			long[] ip = new long[4];
//			// 鍏堟壘鍒癐P鍦板潃瀛楃涓蹭腑.鐨勪綅缃�
//			int position1 = strIP.indexOf(".");
//			int position2 = strIP.indexOf(".", position1 + 1);
//			int position3 = strIP.indexOf(".", position2 + 1);
//			// 灏嗘瘡涓�.涔嬮棿鐨勫瓧绗︿覆杞崲鎴愭暣鍨�
//			ip[0] = Long.parseLong(strIP.substring(0, position1));
//			ip[1] = Long.parseLong(strIP.substring(position1 + 1, position2));
//			ip[2] = Long.parseLong(strIP.substring(position2 + 1, position3));
//			ip[3] = Long.parseLong(strIP.substring(position3 + 1));
//			return (ip[0] << 24) + (ip[1] << 16) + (ip[2] << 8) + ip[3];
//		}
//		return 0;
//	}
	
	/**
	 * 鑾峰彇璇锋眰鐨処P鍦板潃
	 * 锛堣幏鍙朓P鐨勪俊鎭疉PI:http://ip.taobao.com/service/getIpInfo.php?ip={IP}锛�
	 * @param request
	 * @return
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		if (ip.equals("0:0:0:0:0:0:0:1")) {
			ip = "鏈湴";
		}
		if (ip.split(",").length > 1) {
			ip = ip.split(",")[0];
		}
		return ip;
	}
	
	/**
	 * 鏄惁鏄唴缃慖P 
	 * @param ipAddress IP鍦板潃
	 * @return
	 */
//	public static boolean isInnerIP(String ipAddress) {
//		boolean isInnerIp = false;
//		long ipNum = ipv4ToLong(ipAddress);
//
//		long aBegin = ipv4ToLong("10.0.0.0");
//		long aEnd = ipv4ToLong("10.255.255.255");
//
//		long bBegin = ipv4ToLong("172.16.0.0");
//		long bEnd = ipv4ToLong("172.31.255.255");
//
//		long cBegin = ipv4ToLong("192.168.0.0");
//		long cEnd = ipv4ToLong("192.168.255.255");
//
//		isInnerIp = isInner(ipNum, aBegin, aEnd) || isInner(ipNum, bBegin, bEnd) || isInner(ipNum, cBegin, cEnd) || ipAddress.equals(LOCALHOST_IP);
//		return isInnerIp;
//	}
	
	private static boolean isInner(long userIp, long begin, long end) {
		return (userIp >= begin) && (userIp <= end);
	}
	
	/**
	 * 妫�娴嬫湰鍦扮鍙ｅ彲鐢ㄦ��
	 * @param port 琚娴嬬殑绔彛
	 * @return 鏄惁鍙敤
	 */
	public static boolean isUsableLocalPort(int port) {
		if (false == isValidPort(port)) {
			return false;
		}
		try {
			new Socket(LOCALHOST_IP, port).close();
			return false;
		} catch (Exception e) {
			return true;
		}
	}

	/**
	 * 鏄惁涓烘湁鏁堢殑绔彛
	 * @param port 绔彛鍙�
	 * @return 鏄惁鏈夋晥
	 */
	public static boolean isValidPort(int port) {
		return port >= 0 && port <= 0xFFFF;
	}
	
	/**
	 * 鑾峰彇鏈満鍑虹幇鐨勭涓�涓狹AC鍦板潃(鏆傛椂鍙敮鎸亀indows銆丩inux銆乁NIX鎿嶄綔绯荤粺)
	 * @return
	 */
	public static String getMACAddress() {
		String osName=System.getProperty("os.name").toLowerCase();
		String mac = null;
		BufferedReader bufferedReader = null;
		Process process = null;
		try {
			if (osName.startsWith("windows")) 
				process = Runtime.getRuntime().exec("ipconfig /all");
			else if(osName.startsWith("linux")) 
				process = Runtime.getRuntime().exec("ifconfig eth0");
			else if(osName.startsWith("unix"))
				process = Runtime.getRuntime().exec("ifconfig eth0");
			bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line = null;
			int index = -1;
			while ((line = bufferedReader.readLine()) != null) {
				if (osName.startsWith("windows")){
					if (line.split("-").length == 6){
						index = line.indexOf(":");
						if (index != -1) mac = line.substring(index + 1).trim();
						break;
					}
					index = line.toLowerCase().indexOf("鐗╃悊鍦板潃");
					if (index != -1) {
						index = line.indexOf(":");
						if (index != -1) mac = line.substring(index + 1).trim();
						break;
					}
				}else if(osName.startsWith("linux")){
					index = line.toLowerCase().indexOf("纭欢鍦板潃");
					if (index != -1) {
						mac = line.substring(index + 4).trim();
						break;
					}
				}else if(osName.startsWith("unix")){
					index = line.toLowerCase().indexOf("hwaddr");
					if (index != -1) {
						mac = line.substring(index + "hwaddr".length() + 1).trim();
						break;
					}
				}

			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (bufferedReader != null) {
					bufferedReader.close();
				}
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			bufferedReader = null;
			process = null;
		}

		return mac;
	}
	
	/**
	 * 鏍规嵁IP鑾峰彇褰撳墠鐢佃剳(閫傞厤鍣ㄧ姸鎬�) 鎸囧畾 IP 鍦板潃鐨勮繙绋嬫満鍣ㄧ殑MAC鍦板潃
	 * @param ip 闇�瑕佽幏鍙朚AC鍦板潃鐨処P
	 * @return
	 * @throws Exception
	 */
	public static String getMACAddress(String ip) throws Exception {  
	    String line = "";  
	    String macAddress = "";  
	    final String MAC_ADDRESS_PREFIX = "MAC Address = ";  
	    if (LOCALHOST_IP.equals(ip)) {  
	        InetAddress inetAddress = InetAddress.getLocalHost();  
	        byte[] mac = NetworkInterface.getByInetAddress(inetAddress).getHardwareAddress();  
	        StringBuilder sb = new StringBuilder();  
	        for (int i = 0; i < mac.length; i++) {  
	            if (i != 0) {  
	                sb.append("-");  
	            }  
	            String s = Integer.toHexString(mac[i] & 0xFF);  
	            sb.append(s.length() == 1 ? 0 + s : s);  
	        }  
	        macAddress = sb.toString().trim().toUpperCase();  
	        return macAddress;  
	    }  
	    try {  
	        Process p = Runtime.getRuntime().exec("nbtstat -A " + ip);  
	        InputStreamReader isr = new InputStreamReader(p.getInputStream());  
	        BufferedReader br = new BufferedReader(isr);  
	        while ((line = br.readLine()) != null) {  
	            if (line != null) {  
	                int index = line.indexOf(MAC_ADDRESS_PREFIX);  
	                if (index != -1) {  
	                    macAddress = line.substring(index + MAC_ADDRESS_PREFIX.length()).trim().toUpperCase();  
	                }  
	            }  
	        }  
	        br.close();  
	    } catch (IOException e) {  
	        e.printStackTrace(System.out);  
	    }  
	    return macAddress;  
	}
	
	
	/**
	 * 绠�鏄撶殑浣跨敤Socket鍙戦�佹暟鎹�
	 * @param host Server涓绘満
	 * @param port Server绔彛
	 * @param isBlock 鏄惁闃诲鏂瑰紡
	 * @param data 闇�瑕佸彂閫佺殑鏁版嵁
	 * @throws IORuntimeException IO寮傚父
	 */
	public static boolean sendSocket(String host, int port, boolean isBlock, ByteBuffer data) {
		try (SocketChannel channel = SocketChannel.open(new InetSocketAddress(host, port))) {
			channel.configureBlocking(isBlock);
			channel.write(data);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 浣跨敤鏅�歋ocket鍙戦�佹暟鎹�
	 * @param host Server涓绘満
	 * @param port Server绔彛
	 * @param data 鏁版嵁
	 * @throws IOException IO寮傚父
	 */
	public static boolean sendSocket(String host, int port, byte[] data) throws IOException {
		OutputStream out = null;
		try (Socket socket = new Socket(host, port)) {
			out = socket.getOutputStream();
			out.write(data);
			out.flush();
			return true;
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			out.close();
		}
		return false;
	}
	
	public NetworkTools() {
		throw new Error("Do not need instantiate!");
	}
	
}
